#include "sys_gpio.h"
#include "sys_uart.h"
#include "sys_delay.h"
#include "sys_IO_I2C.h"

#define uchar unsigned char 
#define uint  unsigned int 
//GPIO定义
#define SDA_PORT GPIOA
#define SCL_PORT GPIOA
#define SDA_PIN GPIO_Pin_2
#define SCL_PIN GPIO_Pin_0

#define sda_in GPIO_READ(SDA_PORT,SDA_PIN) 
#define sda_1  GPIO_SET(SDA_PORT,SDA_PIN) 
#define sda_0  GPIO_RESET(SDA_PORT,SDA_PIN) 

#define scl_1  GPIO_SET(SDA_PORT,SCL_PIN) 
#define scl_0  GPIO_RESET(SDA_PORT,SCL_PIN) 

#define delay()         delay_us(1)

#define set_sda_out()   GPIO_Congif(SDA_PORT,SDA_PIN,GPIO_Mode_OUT,GPIO_PuPd_UP)
#define set_sda_in()    GPIO_Congif(SDA_PORT,SDA_PIN,GPIO_Mode_IN,GPIO_PuPd_UP)


/*start---------------------------
*/
int start(void)
{
  //------------------
  scl_1;
  delay();	
  scl_0;	
  delay();		
  scl_1;		
  delay();
  scl_0;	
  delay();	
  scl_1;
  //------------------
  
  set_sda_in();	
  delay();
  
  if(!sda_in)
  {
    sysprintf("err:bus busy!");
    return -1;	//SDA线为低电平则总线忙,退出
  }
  set_sda_out();
  sda_0;
  delay();
  
  sda_0;
  delay();
  
  return 0;
}
/*stop---------------------------
*/
void stop(void)
{
  
  delay(); 
  scl_0;	
  sda_0;
  scl_1;		
  delay();
  sda_1;
  delay(); 
  scl_0;	
  delay();
  
}
/*ack---------------------------
*/ 
void ack(void)
{
  volatile int i=0;
  set_sda_in();//GT911-改变输入要放前面，不然有问题
  sda_1;
  delay();
  scl_1;	
  delay();
  do{
    if(sda_in==0)break;
    i++;
  }while(i<50000);
  if(i>=50000)sysprintf("ack timeout!\r\n"); 
  set_sda_out();
  scl_0;
}

/*noack---------------------------
*/
void noack(void)
{
  sda_0;
  scl_1;
  delay();
  scl_0;
}
/*iic_write_byte--------------------------
*/
void iic_write_byte(uchar dat)
{
  uchar i;
  scl_0;
  for(i=0;i<8;i++)
  {
    //--------------- 	 
    if(dat&0x80)sda_1;
    else sda_0;
    delay(); 
    dat=dat<<1;
    //---------------  
    scl_1; 		 
    delay();
    scl_0;
    delay(); 	 
  }
  
}
/*iic_read_byte--------------------------
*/
uchar iic_read_byte(void)
{
  uchar i;
  uchar dat=0;
  scl_0;
  set_sda_in();
  delay();
  for(i=0;i<8;i++)
  { 
    scl_1;	 
    delay(); 
    //--------------- 	 
    dat=dat<<1;
    if(sda_in)dat++;
    //--------------- 
    scl_0;
    delay();
    
  }
  set_sda_out();
  sda_1;
  return dat;  
}
/*set_slave_addr-------------------------
*/
u8 IO_slave_addr=0;
void IO_set_slave_addr(u8 addr)
{
  IO_slave_addr=addr;
}
/*write_byte-------------------------
addr 地址
addr_len 地址长度
buf 缓存
buf_len 缓存长充
*/
void IO_write_byte(u16 addr,u8 addr_len,u8* buf,u16 buf_len)
{
  int i=0;
  
  start();
  //写器件地址
  iic_write_byte(IO_slave_addr);
  ack();
  //写内存地址
  if(addr_len==1)
  {
    iic_write_byte(addr&0xff);
    ack();	  
  }
  else if(addr_len==2)
  {
    iic_write_byte(addr>>8);
    ack();
    iic_write_byte(addr&0xff);
    ack();	 
  } 
  //写数据
  for(i=0;i<buf_len;i++)
  {
    iic_write_byte(buf[i]);
    ack();
  }
  stop(); 
}
/*read_byte-------------------------
addr 地址
addr_len 地址长度
buf 缓存
buf_len 缓存长充
*/ 
void IO_read_byte(u16 addr,u8 addr_len,u8* buf,u16 buf_len)
{
  int i=0;
  start();
  //写器件地址	
  iic_write_byte(IO_slave_addr);
  ack();
  //写内存地址
  if(addr_len==1)
  {
    iic_write_byte(addr&0xff);
    ack();	  
  }
  else if(addr_len==2)
  {
    iic_write_byte(addr>>8);
    ack();
    iic_write_byte(addr&0xff);
    ack();
  } 
  //读数据
  start();
  iic_write_byte(IO_slave_addr|0x01);
  ack();
  
  for(i=0;i<buf_len;i++)
  {
    buf[i]=iic_read_byte();
    noack();
  }
  stop();	
}
/*I2C_Init-------------------------
*/ 
void IO_I2C_Init(void)
{
  //GPIOA 没有上下拉 
  GPIO_Congif(SDA_PORT,SDA_PIN,GPIO_Mode_OUT,GPIO_PuPd_UP);
  GPIO_Congif(SDA_PORT,SCL_PIN,GPIO_Mode_OUT,GPIO_PuPd_UP);
  sda_1;
  scl_1;	
}
/*I2C_Demo_读写24Cxx-------------------------
*/ 
void IO_AT24C256_Demo(void)
{
#define LEN 10
  int i;
  u8 buff_in[LEN];
  u8 buff_out[LEN];
  for(i=0;i<LEN;i++)
  {
    buff_in[i]=i&0xff;
    buff_out[i]=0;
  }
  sysprintf("I2C_Demo...\r\n");
  IO_I2C_Init();
  IO_set_slave_addr(0xa0);	
  sysprintf("write...\r\n");
  IO_write_byte(0,2,buff_in,LEN);
  //延时,等EEPROM完成
  delay_ms(10);
  sysprintf("read...\r\n");
  IO_read_byte(0,2,buff_out,LEN);
  sysprintf("   write : read\r\n");
  int a=0;
  for(i=0;i<LEN;i++)
  {
    sysprintf("[%d]   %02x : %02x\r\n",i,buff_in[i],buff_out[i]);
    if(buff_in[i]==buff_out[i])a++;
  }
  if(a==LEN)sysprintf("read and write ok.\r\n");
  else sysprintf("read and write err!!!\r\n");
  while(1);
}

